/**
 * 
 */
package server.internal;

import static commons.Preconditions.check;
import static commons.Preconditions.checkNotNull;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

import server.StorageUnit;
import server.StorageUnitID;

/**
 * @author armstrong
 * 
 */
public class DefaultStorageUnit implements StorageUnit {

	/**
	 * @param storageDeviceDirectory
	 * @param storageUnitId
	 * @return
	 * @throws IOException
	 */
	public static DefaultStorageUnit createStorageUnit(
			final String storageDeviceDirectory,
			final StorageUnitID storageUnitId) throws IOException {

		return new DefaultStorageUnit(storageDeviceDirectory, storageUnitId);
	}

	private final RandomAccessFile	rafToStorageUnit;
	private final FileChannel		channelToStorageUnit;

	private final File				fileToStorageUnit;

	private DefaultStorageUnit(final String storageDeviceDirectory,
								final StorageUnitID storageUnitId)
			throws IOException {

		checkNotNull("storageDeviceDirectory must not be null.",
				storageDeviceDirectory);
		checkNotNull("storageUnitId must not be null.", storageUnitId);

		checkParentDirectoryExists(storageDeviceDirectory);

		fileToStorageUnit = new File(getStorageUnitPath(storageDeviceDirectory,
				storageUnitId));
		// FIXME assert the file is created
		fileToStorageUnit.createNewFile();
		rafToStorageUnit = new RandomAccessFile(fileToStorageUnit, "rw");
		channelToStorageUnit = rafToStorageUnit.getChannel();
	}

	private void checkParentDirectoryExists(final String storageDeviceDirectory) {

		final File parentDirectory = new File(storageDeviceDirectory);
		check("storageDeviceDirectory must exist to create StorageUnit.",
				parentDirectory.exists());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see server.StorageUnit#delete()
	 */
	@Override
	public void delete() throws IOException {

		if (!fileToStorageUnit.delete()) {

			throw new IOException("Could not delete StorageUnit");
		}
	}

	private String getStorageUnitPath(final String storageDeviceDirectory,
			final StorageUnitID storageUnitId) {

		return storageDeviceDirectory + File.separator + storageUnitId.getId();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see server.StorageUnit#read(java.nio.ByteBuffer)
	 */
	@Override
	public int read(final ByteBuffer bytes) throws IOException {

		return channelToStorageUnit.read(bytes);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see server.StorageUnit#seek(long)
	 */
	@Override
	public void seek(final long size) throws IOException {

		channelToStorageUnit.position(size);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see server.StorageUnit#setSize(long)
	 */
	@Override
	public void setSize(final long size) throws IOException {
		rafToStorageUnit.setLength(size);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see server.StorageUnit#size()
	 */
	@Override
	public long size() throws IOException {
		return rafToStorageUnit.length();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see server.StorageUnit#write(java.nio.ByteBuffer)
	 */
	@Override
	public int write(final ByteBuffer bytes) throws IOException {

		return channelToStorageUnit.write(bytes);
	}
}
